/**
 *    TimedProfiles - let Android perform tasks based on conditions
 *    Copyright (C) 2011  Daniel Weinhold
 *
 *    This program is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * */
package de.drak.Profiles;

import java.lang.reflect.Method;
import java.util.Calendar;

import android.app.Activity;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.TabActivity;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.database.Cursor;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.text.format.DateUtils;
import android.util.DisplayMetrics;
import android.view.Window;
//import android.util.Log;
import android.widget.TabHost;

/**Main Class
 * 
 * Creates a GUI whit tabs showing RuleList, ProfileList and Options
 * Provides also some static functions
 * */
public class TimedProfiles extends TabActivity {

	/**display state to user*/
	public static final String INTENT_INFO_STR   = "com.twofortyfouram.locale.intent.extra.BLURB";
	/**name - "path"*/
	public static final String INTENT_TITLE      = "com.twofortyfouram.locale.intent.extra.BREADCRUMB";
	/**unset bundle - it is send to the app on deactivation*/
	public static final String INTENT_BUNDLE_UNSET = "de.drak.Profiles.intent.extra.UNSET";
	/**when to check next*/
	public static final String INTENT_BUNDLE_NEXT_CHECK = "de.drak.Profiles.intent.extra.NEXT_CHECK";
	//public static final String INTENT_BRODCASTER = "com.twofortyfouram.locale.intent.extra.ACTION_FIRE"; //other broadcaster than std

	/**Edit a Condition*/
	public static final String ACTION_CON_EDIT   = "com.twofortyfouram.locale.intent.action.EDIT_CONDITION";
	/**Send WUSAAA to Condition*/
	public static final String ACTION_CON_QUERY  = "com.twofortyfouram.locale.intent.action.QUERY_CONDITION";
	/**Edit a Setting*/
	public static final String ACTION_SET_EDIT   = "com.twofortyfouram.locale.intent.action.EDIT_SETTING";
	/**Execute a Setting*/
	public static final String ACTION_SET_FIRE   = "com.twofortyfouram.locale.intent.action.FIRE_SETTING";
	//TODO astrid dont listens for ACTION_SET_FIRE, it sets one itself

	/**Tell Intelligent Profiles to check a Plugin*/
	public static final String ACTION_REQUEST   = "com.twofortyfouram.locale.intent.action.REQUEST_QUERY";
	/**Name of Activity that likes to be fired*/
	public static final String INTENT_PACKAGE   = "com.twofortyfouram.locale.intent.extra.ACTIVITY";

	/**Result of Condition that is not ready*/
	public static final int RESULT_CONDITION_UNKNOWN = 18;
	/**Result of Condition that is true*/
	public static final int RESULT_CONDITION_SATISFIED = 16;
	/**Result of Condition that is false*/
	public static final int RESULT_CONDITION_UNSATISFIED = 17;
	/**Result of Edit Activity that wants to be removed*/
	public static final int RESULT_REMOVE = 15;
	
	/**Used to build a title path*/
	public static final String INTENT_TITLE_SEPERATOR = " > ";
	
	public static int min_icon_h;
	public static int max_icon_h;
	public static boolean car_mode;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
        setContentView(R.layout.main);
        
        car_mode = false;
        if(Integer.parseInt(android.os.Build.VERSION.SDK) >= 8)//check if car mode is active
        {
        	Object mService;
        	Method method = null;
			Integer state = 0;
        	mService = getSystemService("uimode");
        	do
        	{
	        	if (mService == null){break;}
	        	
	        	try {
					method = mService.getClass().getMethod("getCurrentModeType");
				} catch (Exception e) {
					e.printStackTrace();
					break;
				}
				if (method != null) method.setAccessible(true);
				
				try {
					state = (Integer) method.invoke(mService);
				} catch (Exception e) {
					e.printStackTrace();
					break;
				}
        	}while(false);

        	car_mode = state==3;
        }
        
        Resources res = getResources(); // Resource object to get Drawables
        TabHost tabHost = getTabHost();  // The activity TabHost
        TabHost.TabSpec spec;  // Resusable TabSpec for each tab
        Intent intent;  // Reusable Intent for each tab

        //RuleList
        // Create an Intent to launch an Activity for the tab (to be reused)
        intent = new Intent().setClass(this, RuleList.class);

        // Initialize a TabSpec for each tab and add it to the TabHost
        spec = tabHost.newTabSpec("rules").setIndicator(getString(R.string.rules),
                          res.getDrawable(R.drawable.rules))
                      .setContent(intent);
        tabHost.addTab(spec);
        
        // ProfileList
        intent = new Intent().setClass(this, ProfileList.class);
        spec = tabHost.newTabSpec("profiles").setIndicator(getString(R.string.profiles),
        				res.getDrawable(R.drawable.profiles))
                      .setContent(intent);
        tabHost.addTab(spec);
        
        if(!car_mode)
        {
	        // Options
	        intent = new Intent().setClass(this, Options.class);
	        spec = tabHost.newTabSpec("opts").setIndicator(getString(R.string.opts),
	        				res.getDrawable(android.R.drawable.ic_menu_preferences))
	                      .setContent(intent);
	        tabHost.addTab(spec);
        }
        //tabs done

        tabHost.setCurrentTab(1);

		final DisplayMetrics metrics = new DisplayMetrics();
		getWindowManager().getDefaultDisplay().getMetrics(metrics);
		final float Density = metrics.density;
		max_icon_h = (int)(48*Density+0.5);
		min_icon_h = (int)(41*Density+0.5);
		
		//set timer
        aktTimer(this.getApplicationContext());
        
        Database db = new Database(this);
        db.open();
        long d = db.getNextDeadLine();
        db.close();
        if(d!=0)
        {
        	aktTimerOnce(this.getApplicationContext(), d);
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
    }

    /**
     * Setup a periodic check
     * 
     * @param c Context
     */
    static void aktTimer(final Context c)
    {
    	aktTimer(c, 2000);
    }

    /**
     * Setup a periodic check starting in deltaT MilliSecs
     * 
     * @param c Context
     * @param deltaT millisecond value
     */
    static void aktTimer(final Context c, long deltaT)
    {
        Intent bla = new Intent(c, ConditionCecker.class);
        bla.setAction(ConditionCecker.ACTION_TIMER);
        final PendingIntent operation = PendingIntent.getService(c, 0, bla, 0);
        AlarmManager timer = (AlarmManager) c.getSystemService(Context.ALARM_SERVICE);

        SharedPreferences p = PreferenceManager.getDefaultSharedPreferences(c);
   
        int mins;
        try{
        	mins = Integer.parseInt(p.getString("check_intervall", "1"));
        }catch(NumberFormatException e)
        {
        	mins = 1;
        }
        
        timer.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()+deltaT, mins*DateUtils.MINUTE_IN_MILLIS, operation);
		//Log.i("ConditionCecker",  "periodicTimer on "+mins);
    }
    /**
     * End periodic checks
     * 
     * @param c Context
     */
    static void deaktTimer(final Context c)
    {
        Intent bla = new Intent(c, ConditionCecker.class);
        bla.setAction(ConditionCecker.ACTION_TIMER);
        final PendingIntent operation = PendingIntent.getService(c, 0, bla, 0);
        AlarmManager timer = (AlarmManager) c.getSystemService(Context.ALARM_SERVICE);
        timer.cancel(operation);
    }
    /**
     * Setup a single check at time X
     * 
     * @param c Context
     * @param checkDate
     */
    static void aktTimerOnce(final Context c, long checkDate)
    {
        Intent bla = new Intent(c, ConditionCecker.class);
        bla.setAction(ConditionCecker.ACTION_DEADLINE);
        final PendingIntent operation = PendingIntent.getService(c, 0, bla, 0);
        AlarmManager timer = (AlarmManager) c.getSystemService(Context.ALARM_SERVICE);
        timer.set(AlarmManager.RTC_WAKEUP, checkDate, operation);

        
        Calendar s = Calendar.getInstance();
    	s.setTimeInMillis(checkDate);/*
    	Log.i("ConditionCecker",  "deadline in "+s.get(Calendar.DAY_OF_MONTH)+"."+
    	    	(1+s.get(Calendar.MONTH))+"."+
    	    	s.get(Calendar.YEAR)+" "+
    	    	s.get(Calendar.HOUR_OF_DAY)+":"+
    	    	s.get(Calendar.MINUTE)+":"+
    	    	s.get(Calendar.SECOND));*/
    }
    
    /**
     * Opens a Setting-Plug-In to set its Settings
     * 
     * @param name Name of the class
     * @param bundle store_foreward data
     * @param c Context
     */
    static void setPlugInSettings(final ComponentName name, final Bundle bundle, final Context c)
    {
		Intent result = new Intent(ACTION_SET_FIRE);
		result.setComponent(name);
		if(bundle!=null){
			//result.putExtra(INTENT_BUNDLE, bundle);
			result.putExtras(bundle);
		}
		c.sendBroadcast(result);
    }
    /**
     * Opens an Activity to Edit the Settings of a Setting-Plug-In.
     * Activity will return
     *  - RESULT_OK: INTENT_INFO_STR and INTENT_BUNDLE are Set
     *  - RESULT_CANCELED: don't do anything
     *  - or RESULT_REMOVE: delete the Plugin from the List
     * @param name Name of the class
     * @param bundle store_foreward data
     * @param reqCode If >= 0, this code will be returned in onActivityResult() when the activity exits.
     * @param dad Activity that starts the new one
     */
    static void editPlugInSetting(final ComponentName name, final Bundle bundle, final int reqCode, Activity dad)
    {
		Intent result = new Intent(ACTION_SET_EDIT);
		result.setComponent(name);
		result.putExtra(INTENT_TITLE, dad.getTitle().toString());
		if(bundle!=null){
			//result.putExtra(INTENT_BUNDLE, bundle);
    		result.putExtras(bundle);
		}
    	try
    	{
    		dad.startActivityForResult(result,reqCode);
    	}catch(ActivityNotFoundException e)
    	{
    		
    	}
    }
    /**
     * Opens an Activity to Edit the Settings of a Condition-Plug-In.
     * Activity will return
     *  - RESULT_OK: INTENT_INFO_STR and INTENT_BUNDLE are Set
     *  - RESULT_CANCELED: don't do anything
     *  - or RESULT_REMOVE: delete the Plugin from the List
     * @param name Name of the class
     * @param bundle store_foreward data
     * @param reqCode If >= 0, this code will be returned in onActivityResult() when the activity exits.
     * @param dad Activity that starts the new one
     */
    static void editPlugInState(final ComponentName name, final Bundle bundle, final int reqCode, Activity dad)
    {
		Intent result = new Intent(ACTION_CON_EDIT);
		result.setComponent(name);
		result.putExtra(INTENT_TITLE, dad.getTitle().toString());
		if(bundle!=null){
			//result.putExtra(TimedProfiles.INTENT_BUNDLE, bundle);
			result.putExtras(bundle);
		}
    	try
    	{
    		dad.startActivityForResult(result,reqCode);
    	}catch(ActivityNotFoundException e)
    	{
    		
    	}
    }
    /**
     * Opens a Condition-Plug-In to check its State
     * resultReceiver's getResultCode will be
     *  - RESULT_CONDITION_SATISFIED: Condition is true
     *  - RESULT_CONDITION_UNSATISFIED: Condition is false
     *  - or RESULT_CONDITION_UNKNOWN: delete the Plugin from the List
     * @param name Name of the class
     * @param bundle store_foreward data
     * @param resultReceiver Your own BroadcastReceiver to be lunched when the result code is recieved
     * @param c Context
     */
    static void queryPlugInState(final ComponentName name, final Bundle bundle, final BroadcastReceiver  resultReceiver, final Context c)
    {
		Intent result = new Intent(ACTION_CON_QUERY);
		result.setComponent(name);
		if(bundle!=null){
			//result.putExtra(INTENT_BUNDLE, bundle);
			result.putExtras(bundle);
		}

		c.sendOrderedBroadcast(result, null, resultReceiver, null, RESULT_CONDITION_UNKNOWN, null, null);
    }
    /**
     * Formats an Activitys Title with the data from its Intent
     * @param dad The Activity
     * @param title Title of the Activity - will be put at the End
     * */
    public static void createTitle(Activity dad, final String title)
    {
		final String breadcrumbString = dad.getIntent().getStringExtra(INTENT_TITLE);
		if (breadcrumbString == null)
		{
			dad.setTitle(title);
			return;
		}
		dad.setTitle(String.format("%s%s%s", breadcrumbString, INTENT_TITLE_SEPERATOR, title));
    }
    
    /**
     * Set a Profile to be Active or not - and run its tasks 
     * @param mDbHelper Database
     * @param c your Context
     * @param ProfID witch profile?
     * @param on 1=act, 0=deact
     */
    public static void ToggelProfile(final Database mDbHelper, final Context c, final Long ProfID, final int on)
    {
    	//run associated tasks
    	Cursor Settings = mDbHelper.fetchProfileSettings(ProfID);
    	if(Settings==null)
    	{
    		return;
    	}
    	final int io = Settings.getColumnIndex(Database.PS_KEY_ON),
		ip = Settings.getColumnIndex(Database.PS_KEY_PLUGIN);
		 do{
			 if(Settings.getInt(io)!=on)
			 {
				 continue;
			 }
			 final Bundle bundle = mDbHelper.fetchPluginStateBundle(Settings.getLong(ip));
			 final ComponentName name = mDbHelper.fetchPluginStateFireComponent(Settings.getLong(ip));
			 if(name != null)
			 {
				 TimedProfiles.setPlugInSettings(name, bundle, c);
			 }
		 }while(Settings.moveToNext() != false);
		 Settings.close();
    	//set checkbox
    	mDbHelper.updateProfile(ProfID, null, on,-1);
    }
}